.message_row {
    display: grid;
    /* Prevent the messagebox column from overflowing the 1fr
       space allotted by specifying `minmax(0,1fr)`, which
       sets 0 as the minimum size, not the grid default of
       `auto`. */
    grid-template: auto auto / 2px minmax(0, 1fr);
    grid-template-areas:
        "date_unread_marker    date_row  "
        "message_unread_marker messagebox";

    border-left: 1px solid var(--color-message-list-border);
    border-right: 1px solid var(--color-message-list-border);
    background-color: var(--color-background-stream-message-content);

    &.private-message {
        background-color: var(--color-background-private-message-content);

        .date_row {
            background-color: var(--color-background-private-message-content);
        }

        .data-container::after {
            background: linear-gradient(
                0deg,
                var(--color-background-private-message-content),
                transparent 100%
            );
        }
    }

    &.direct_mention {
        background-color: var(--color-background-direct-mention);

        .message_embed .data-container::after {
            background: linear-gradient(
                0deg,
                var(--color-background-direct-mention),
                transparent 100%
            );
        }
    }

    &.group_mention {
        background-color: var(--color-background-group-mention);

        .message_embed .data-container::after {
            background: linear-gradient(
                0deg,
                var(--color-background-group-mention),
                transparent 100%
            );
        }
    }

    &.sender_info_hovered {
        .sender_name {
            cursor: pointer;
            /* TODO: Refactor the teetering nested classes
               above so that !important can be removed. */
            color: var(--color-text-sender-name-hover) !important;
        }

        .message-avatar {
            cursor: pointer;
        }
    }
}

.messagebox {
    grid-area: messagebox;
    word-wrap: break-word;
    cursor: pointer;
    border: none;
    /* The left padding value accounts for a 2px
      unread marker, ensuring a uniform 5px of
      padding on either side of the message box. */
    padding: 0 5px 0 3px;

    &:hover .message_controls,
    &:hover .message_failed {
        .empty-star:hover {
            cursor: pointer;
        }

        > .message_control_button {
            opacity: 1;
            visibility: visible;
        }
    }
}

.messagebox-content {
    display: grid;
    align-items: baseline;
    padding-left: 10px;
    /* Prevent the message column from overflowing the 1fr
       space allotted by specifying `minmax(0,1fr)`, which
       sets 0 as the minimum size, not the grid default of
       `auto`.

        The calculated `--message-box-timestamp-column-width`
        should match `max-content` exactly, but `max-content`
        ensures the timestamp will always have enough space
        in the column. */
    grid-template:
        var(--message-box-sender-line-height) repeat(3, auto) /
        var(--message-box-avatar-column-width) minmax(0, 1fr) calc(
            3 * var(--message-box-icon-width)
        )
        8px minmax(var(--message-box-timestamp-column-width), max-content);
    /* Named grid areas provide flexibility for positioning grid items
       reliably, even if the row or column definitions of the grid change. */
    grid-template-areas:
        "edited message   controls . time"
        ".      message   .        . .   "
        ".      more      .        . .   "
        ".      reactions .        . .   ";

    &.content_edit_mode {
        cursor: default;
        /* Set the controls area to 0 to give more space
           to the edit/source view area. */
        grid-template-columns:
            var(--message-box-avatar-column-width) minmax(0, 1fr)
            0 8px minmax(
                var(--message-box-timestamp-column-width),
                max-content
            );
    }

    @media (width < $sm_min), ((width >= $md_min) and (width < $mc_min)) {
        grid-template-columns:
            var(--message-box-avatar-column-width) minmax(0, 1fr) calc(
                2 * var(--message-box-icon-width)
            )
            8px minmax(var(--message-box-timestamp-column-width), max-content);
    }

    .message_controls {
        grid-area: controls;

        @media (width < $sm_min), ((width >= $md_min) and (width < $mc_min)) {
            /* This is intended to target the first message_controls child
               when there are 3 displayed. 4 = 3 + hidden message_failed element. */
            .message_control_button:nth-last-child(4) {
                display: none;
            }
        }
    }

    .message_edit_notice {
        grid-area: edited;
    }

    .slow-send-spinner {
        display: none;
        justify-self: end;
        margin-right: 10px;
        text-align: end;
        grid-area: time;
    }

    .message_content {
        grid-area: message;
        /*
        Space between two single line messages is kept in
        lockstep with adjacent Markdown elements.
        */
        padding: var(--message-box-markdown-aligned-vertical-space) 0 0;
        color: var(--color-text-message-default);
        /* We explicitly set line-height here so that
           the message area is not beholden to the legacy
           `max()` declaration on `body`. */
        line-height: var(--base-line-height-unitless);
        min-height: 17px;
        display: block;
        position: relative;
        overflow: hidden;

        &:empty {
            display: none;
        }

        &.condensed {
            max-height: 8.5em;
            min-height: 0;
            overflow: hidden;
            mask-image: linear-gradient(
                to top,
                hsl(0deg 0% 100% / 0%) 0%,
                hsl(0deg 0% 100%) 60px
            );
            mask-size: cover;
        }

        &.collapsed {
            padding: 0;
            max-height: 0;
            min-height: 0;
            overflow: hidden;
        }
    }

    .message_reactions {
        grid-area: reactions;
        display: flex;
        /* Allow reactions to wrap in mobile viewports */
        flex-wrap: wrap;
        /* Keep reactions aligned to start (top), so that the
           margin on the reaction button doesn't appear to
           stretch the reactions taller. */
        align-items: flex-start;
        /* Control reaction spacing with a gap */
        gap: 4px;
    }

    .message_edit {
        grid-area: message;
        /* Align self to start, rather than baseline, so the baseline
          is preserved from the message itself--keeping the time,
          edit message, and controls at the same vertical alignment. */
        align-self: start;
        margin-top: var(--message-box-vertical-margin);
    }

    .message_length_controller {
        grid-area: more;
    }

    .collapsed ~ .message_length_controller {
        /* When content is collapsed, the length controller
           should occupy the space ordinarily assigned to
           the message. */
        grid-area: message;
        /* However, don't let the SHOW MORE button participate
           in the baseline group. */
        align-self: start;

        .message_length_toggle {
            /* Ensure that a collapsed message maintains the
               same space around the toggle button as any other
               message-row content. */
            margin: 4px 0;
        }
    }

    &.content_edit_mode .message_length_controller {
        /* If entering edit mode on a collapsed message,
           just hide the controller area. This preserves
           the collapsed state of the message, which need
           not be touched. We just need to hide the button.
           This works for condensed messages, too. */
        display: none;
    }
}

.messagebox-includes-sender {
    .messagebox-content {
        grid-template-areas:
            "avatar sender    controls . time"
            "avatar message   .        . .   "
            ".      more      .        . .   "
            ".      reactions .        . .   ";

        .message_edit {
            /* No top margin when there's a sender row */
            margin-top: 0;
        }

        &.is-me-message {
            grid-template-areas:
                "avatar sender    controls . time"
                "avatar sender    .        . .   "
                ".      more      .        . .   "
                ".      reactions .        . .   ";

            .message-avatar {
                /* Set the line-height to match the height of the avatar image
                   to center me-messages within the baseline group. */
                line-height: var(--message-box-avatar-height);
                align-self: baseline;
                /* Because the avatar may be the tallest element in a
                   single-line me message, this margin preserves the
                   overall height of the message box. */
                margin-bottom: var(--message-box-vertical-margin);
            }

            .message_sender {
                /* Don't display message sender as flexbox for me-messages. */
                display: block;
                /* Set the same line-height as on message content for
                   me-messages. */
                line-height: var(--base-line-height-unitless);
                /* Ensure the same spacing below messages as for any other
                   paragraph. */
                padding-bottom: var(
                    --message-box-markdown-aligned-vertical-space
                );

                /* Display message components inline, with wrapping white-space,
                   so the sender name and message display as a continuous line
                   of wrapping text. */
                .sender_name {
                    white-space: normal;
                    display: inline;
                }

                .sender_name_text {
                    max-width: 100%;
                }
            }

            &.content_edit_mode {
                .message_sender {
                    /* Keep the me-message participating in the baseline */
                    visibility: hidden;
                }

                .message_edit {
                    /* Use the sender grid area for the me-message edit/view-source box */
                    grid-area: sender;
                    margin-top: var(--message-box-vertical-margin);
                }
            }
        }

        .message-avatar {
            grid-area: avatar;
            /* The picture should not participate in the baseline group. */
            align-self: start;
            margin-top: var(--message-box-vertical-margin);
        }

        .status-message {
            font-weight: normal;
        }

        .message_content {
            /* Pull message content up closer to sender to
               let the text baseline sit adjacent the bottom
               of the avatar. We also need to account for the
               padding atop .message_content. */
            margin-top: calc(
                (var(--message-box-markdown-aligned-vertical-space) * 0.5 * -1) -
                    var(--message-box-markdown-aligned-vertical-space)
            );
            grid-area: message;
        }

        .slow-send-spinner {
            align-self: center;
            position: unset;
            margin-top: 1px;
        }

        .message_edit_notice {
            /* When the edit notice is inline, as on edited me-messages,
              the inline-block and accompanying vertical-align styles will
              apply */
            display: inline-block;
            vertical-align: baseline;
            /* A bit of margin here helps these not look associated with the name. */
            margin-left: 4px;
            /* Unset the padding used on edited notices under the avatar. */
            padding-right: 0;
        }

        .message_sender {
            overflow: hidden;
            text-overflow: ellipsis;
            grid-area: sender;
            display: flex;
            /* A generous line-height on the sender name is necessary
               for internationalization and non-Western Latin character
               sets. */
            line-height: var(--message-box-sender-line-height);
            /* Ensure flexed sender info (name, status emoji, inline EDITED)
               forms a baseline group, which will participate with the
               message-box grid's baseline group, too. */
            align-items: baseline;

            .zulip-icon.zulip-icon-bot {
                font-size: 12px;
                align-self: center;
                padding: 0 0 0 5px;
            }

            .sender_name {
                display: inline-flex;
                font-weight: 700;
                color: var(--color-text-sender-name);
                column-gap: 3px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                outline: none;
                align-self: baseline;

                .sender_name_text {
                    overflow: hidden;
                    white-space: nowrap;
                    display: inline-flex;

                    .user-name {
                        overflow: hidden;
                        text-overflow: ellipsis;
                    }
                }
            }
        }
    }
}

.message_controls {
    display: flex;
    align-items: baseline;
    font-size: 16px;
    /* This is a bit tricky; we need to reserve space for the message
       controls even when the message isn't hovered, so that hover
       doesn't disturb the layout.  Usually that would be just
       visibility: hidden, but that cannot be animated, so we set
       opacity as well, which can be animated. */
    .message_control_button {
        opacity: 0;
        visibility: hidden;
        transition: all 0.2s ease;
        width: var(--message-box-icon-width);
        height: var(--message-box-icon-height);
        text-align: center;
        color: var(--color-message-action-visible);

        & .message-controls-icon {
            vertical-align: middle;
            /* TODO: Math for these values, possibly with variables.
               In short, the icon body is 16px square; the current
               area for the icon is 26px wide by 25px tall, so these
               values ensure a 26px x 25px clickable area for the icon. */
            padding: 2.5px 3px;

            &::before {
                /* We specify block display so the
                   scaling transform below works as
                   expected. */
                display: block;
            }

            &:active::before {
                transform: scale(0.92);
                transform-origin: center;
                outline: 0;
            }

            &:focus {
                /* Remove the outline but do not color on focus;
                   focus-visible is more appropriate for the color
                   changes, as it only applies color when focus
                   is achieved from a keyboard or other pointerless
                   device. */
                outline: 0;
            }

            &:hover,
            &:focus-visible {
                outline: 0;
                color: var(--color-message-action-interactive);
            }

            /* Separate hover colors for stars */
            &.star:hover,
            &.star:focus-visible {
                color: var(--color-message-star-action);
            }
        }

        .zulip-icon-more-vertical {
            /* Increase visual prominence of the vdots. */
            font-size: 21px;
        }
    }

    /* Tooltips should not follow the width restrictions of their parent element. */
    [data-tippy-root] {
        width: max-content;
        word-wrap: unset;
    }

    .edit_content {
        /* Icons for editing content are determined on message hover;
           we set an empty `.edit_content` to have 0 height in order to
           preserve the layout of the other icons prior to any hovering. */
        &:empty {
            height: 0;
        }

        &:hover {
            cursor: pointer;
        }
    }

    .message_failed {
        display: inline-flex;
        justify-content: space-between;
        cursor: pointer;
        position: relative;
        vertical-align: middle;
        padding-left: 2px;

        &.hide {
            display: none;
        }

        .rotating {
            display: inline-block;
            outline: none;

            animation: rotate 1s infinite linear;
        }

        .failed_message_action {
            opacity: 1 !important;
            color: var(--color-failed-message-send-icon);
            font-weight: bold;
            padding: 1px;
        }

        .message_control_button {
            visibility: inherit;
        }
    }

    .star_container {
        &:not(.empty-star) {
            /* Color, opacity, and visibility, as though the message is hovered. */
            color: var(--color-message-star-action);
            opacity: 1;
            visibility: visible !important;
        }
    }
}

.unread_marker {
    margin-left: var(--unread-marker-left);
    opacity: 0;
    transition: all 0.3s ease-out;

    &.slow_fade {
        transition: all 2s ease-out;
    }

    &.fast_fade {
        transition: all 0.3s ease-out;
    }

    &.date_unread_marker {
        grid-area: date_unread_marker;

        .unread-marker-fill {
            border-radius: 0 !important;
            height: 100% !important;
        }
    }

    &.message_unread_marker {
        grid-area: message_unread_marker;
    }
}

.unread-marker-fill {
    height: 100%;
    width: 2px;
    background: linear-gradient(
        90deg,
        var(--color-unread-marker) 30%,
        hsl(217deg 64% 59% / 0%)
    );
}

.unread .unread_marker {
    transition: all 0.3s ease-out;
    opacity: 1;
}

.message-time {
    justify-self: end;
    padding-right: 5px;
    /* Maintain first-line baseline regardless of
       what happens in the message-content area (e.g., a
       collapsed message, or source/edit view). This
       line-height also keeps EDITED/MOVED messages
       in place, care of their baseline-group participation
       within the grid. */
    line-height: var(--message-box-sender-line-height);
    grid-area: time;
    display: block;
    /* 13px at 14px/1em */
    font-size: 0.9286em;
    font-weight: 350;
    text-align: end;
    opacity: 0.8;
    color: var(--color-text-default);
    letter-spacing: 0.02em;
    /* Disable blue link styling for the message timestamp link. */
    &:hover {
        text-decoration: none;
        color: var(--color-message-action-interactive);
    }

    &.notvisible {
        /* This happens when message failed to send. We don't want to
           display time but still want it to occupy space. */
        width: 45px !important;
        position: unset !important;
    }
}

/* Message-editing styles */
.message-edit-buttons-and-timer {
    margin-top: 5px;
    display: flex;
    gap: 5px;
    /* Allow items to occupy full height.
       This is especially important for
       buttons that are flex items. */
    align-items: stretch;
}

.message-actions-button {
    box-sizing: border-box;
    /* Display the actions buttons as
       flex containers for positioning
       text and spinners. */
    display: flex;
    align-items: center;
    justify-content: center;
    height: 28px;
    padding: 0 10px;
    border-radius: 4px;
    border: 0;
    line-height: 1;
}

.message_edit_save {
    /* Match Save button's basic colors to
       the compose box Send button. */
    color: var(--color-compose-send-button-icon-color);
    background-color: var(--color-compose-send-button-background);

    &:hover {
        background-color: var(
            --color-compose-send-button-background-interactive
        );
    }

    &:disabled {
        /* Replicate the `.new-style` disabled values,
           without any color shifts. */
        cursor: not-allowed;
        opacity: 0.5;
    }
}

.message_edit_cancel,
.message_edit_close {
    color: var(--color-exit-button-text);
    background: var(--color-exit-button-background);

    &:hover {
        background: var(--color-exit-button-background-interactive);
    }
}

.edit-content-container {
    border-radius: 4px;
    border: 1px solid var(--color-message-content-container-border);
    transition: border 0.2s ease;

    &:has(.message_edit_content:focus) {
        border-color: var(--color-message-content-container-border-focus);
    }
}

.message_edit_content {
    max-height: var(--max-message-edit-height);
    width: 100%;
    min-width: 206px;
    min-height: 52px;
    box-sizing: border-box;
    /* Setting resize as none hides the bottom right diagonal box
       (which even has a background color of its own!). */
    resize: none !important;
    color: var(--color-text-default);
    background-color: hsl(0deg 0% 100%);
    border-radius: 3px;
    vertical-align: middle;
    border: none;
    /* Match textarea padding to compose box and
       message-edit preview area. */
    padding: 5px 5px 0;
    margin: 0;

    box-shadow: none;

    &:focus {
        outline: 0;
    }

    &:read-only,
    &:disabled {
        cursor: not-allowed;
    }
}

/* The selector needs to be written this way to override the specificity
of the base style defined for a read-only textarea in dark mode. */
.message_edit_form .edit-controls textarea.message_edit_content:read-only {
    opacity: 1;
}

.message_edit_countdown_timer {
    text-align: right;
    display: inline;
    color: hsl(0deg 0% 63%);

    &.expired {
        color: hsl(4deg 58% 33%);
    }
}

.message-edit-timer {
    display: none;
    /* Center vertically relative to
       buttons. */
    align-self: center;
    /* Use flexbox to position to far right of
       the Save and Cancel buttons. */
    margin-left: auto;
}

.message-edit-feature-group {
    display: flex;
    align-items: baseline;
    border-radius: 0 0 3px 3px;
    background-color: var(--color-message-formatting-controls-container);
    /* margin on either side to let the border of
       .edit-content-container show through. */
    margin: 0 1px;
}

.message_edit_save .loader {
    display: none;
    height: 28px;
    width: 28px;
}

.edit-controls {
    .btn-wrapper {
        cursor: not-allowed;
    }

    .disable-btn {
        pointer-events: none;
    }
}

.message_edit {
    display: none;
}

/* Reduce some of the heavy padding from Bootstrap. */
.message_edit_form {
    margin-bottom: 10px;
    cursor: default;

    .edit-controls {
        margin-left: 0;
        margin-top: 0;
    }

    .preview_message_area {
        max-height: var(--max-message-edit-height);
    }
}

.message_edit_notice {
    font-size: 10px;
    opacity: 0.5;
    user-select: none;
    white-space: nowrap;
    overflow-x: hidden;
    overflow-x: clip;
    text-overflow: ellipsis;
    padding-right: 5.5px;
}

.fade-in-message {
    animation-name: fadeInMessage;
    animation-duration: 1s;
    animation-iteration-count: 1;

    .message_edit_notice {
        animation-name: fadeInEditNotice;
        animation-duration: 1s;
        animation-iteration-count: 1;
    }
}

.message_edit_notice_hover:hover {
    opacity: 1;
}

/* Locally echoed messages. */
.locally-echoed .message-time {
    opacity: 0;
    /* Don't show pointer when message-time doesn't have a link. */
    cursor: default;
}

/* Show the spinner only for messages that are still locally echoed. */
.locally-echoed .slow-send-spinner {
    display: unset !important;
    cursor: default;
}

.recipient_row {
    /* See https://stackoverflow.com/questions/2717480/css-selector-for-first-element-with-class/8539107#8539107
       for details on how this works */
    .message_row.unread {
        .date_unread_marker {
            display: none;
        }
    }

    /* Select all but the first .message_row.unread,
       and remove the properties set from the previous rule. */
    .message_row.unread ~ .message_row.unread {
        .date_unread_marker {
            display: block;
        }
    }
}

.date_row {
    grid-area: date_row;

    & .timerender-content {
        display: block;
        overflow: hidden;
        text-transform: uppercase;
        font-size: calc(12em / 14);
        font-style: normal;
        font-weight: 600;
        line-height: 17px; /* identical to box height, or 131% */
        text-align: right;
        letter-spacing: 0.04em;
        color: var(--color-date);
        /* Right padding matches time in message row and date in recipient row. */
        padding: 8px 6px 8px 4px;
    }
}
